package entity

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"l_net/pkg/file"
	"net"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
)

type WebServe struct {
	FileInfo   []FileInfo     `json:"fileInfo"`
	Port       string         `json:"port"`
	Hidden     FileState      `json:"hidden"` //0隐藏、1显示、2不存在
	HostList   []file.HostObj //为了方便演示，做的配置文件IP
	Exclude    []file.HostObj `json:"exclude"`
	Include    []file.HostObj `json:"include"`
	excludeMap map[string]file.HostObj
	includeMap map[string]file.HostObj
}

// 配置路径
func NewWebServe(path string) *WebServe {
	w := &WebServe{
		FileInfo: nil,
		HostList: nil,
		Exclude:  nil,
		Include:  nil,
		Hidden:   FileStateHidden,
		Port:     "8080",
	}
	// 读取 JSON 文件
	data, err := ioutil.ReadFile(path)
	if err != nil {
		fmt.Println("读取文件失败:", err)
		return nil
	}

	// 解析 JSON 数组到 Person 切片
	err = json.Unmarshal(data, &w)
	if err != nil {
		fmt.Println("解析 JSON 失败:", err)
		return nil
	}
	//放入到map中方便查找
	w.excludeMap = make(map[string]file.HostObj)
	for _, v := range w.Exclude {
		w.excludeMap[v.IP] = v
	}
	w.includeMap = make(map[string]file.HostObj)
	for _, v := range w.Include {
		w.includeMap[v.IP] = v
	}
	return w
}

func (srv *WebServe) Start() {
	// http://127.0.0.1:8080/user,func是回调函数，用于路由的响应，这个回调函数原型是固定
	http.HandleFunc("/user", srv.userHandler)
	http.HandleFunc("/home", srv.homeHandler)
	http.HandleFunc("/download", srv.downloadHandler)
	// 127.0.0.1:8080/search?folderPath=/Users/jibuzixin/Desktop/ft-2
	http.HandleFunc("/search", srv.searchFilesHandler)

	fmt.Println("Http Server start ...", srv.Port)
	// func ListenAndServe(addr string,handler Handler) error{
	// http.ListenAndServe()
	if err := http.ListenAndServe("127.0.0.1:"+srv.Port, nil); err != nil {
		fmt.Println("http start failed,err:", err)
		return
	}
}

func (srv *WebServe) getHyperlinkByFileInfo(file FileInfo) string {
	var u, labe, li string
	if file.Type == FileTypeDir {
		u = "/search?" + url.Values{"folderPath": {file.Path}}.Encode()
		labe = "<a href =\"" + u + "\">" + file.Name + "</a></br>"
		li = "<li><p style=\"color: " + FileColorDir + ";display: inline;\">Directory: </p>" + labe + "</li>"
	} else {
		u = "/download?" + url.Values{"filePath": {file.Path}}.Encode()
		labe = "<a href =\"" + u + "\">" + file.Name + "</a></br>"
		li = "<li><p style=\"color: " + FileColorFile + ";display: inline;\">File: </p>" + labe + "</li>"
	}
	return li
}

func (srv *WebServe) fileExists(filePath string) bool {
	_, err := os.Stat(filePath)
	if os.IsNotExist(err) {
		return false
	}
	return err == nil
}

func (srv *WebServe) userHandler(writer http.ResponseWriter, request *http.Request) {
	writer.Header().Set("Content-Type", "text/html; charset=utf-8")
	//在user里面做拦截器，用于拦截别的用户访问
	ip, _, _ := net.SplitHostPort(request.RemoteAddr)
	fmt.Println("获取IP: ", ip)
	_, ok := srv.excludeMap[ip]
	if ok {
		writer.Write([]byte("<h1>你被禁止了</h1>"))
		return
	}

	// writer :===> 通过writer将数据返回给客户端
	for _, file := range srv.FileInfo {
		filePath := file.Path
		fileName := file.Name
		fi, err := os.Stat(filePath)
		if err != nil {
			fmt.Println(err)
		}
		//判断文件是否存在
		if srv.fileExists(filePath) {
			//判断文件是否是文件夹
			if fi.IsDir() {
				file.Type = FileTypeDir
			} else {
				file.Type = FileTypeFile
			}
			//判断文件是否是隐藏文件
			if strings.HasPrefix(fileName, ".") {
				file.State = FileStateHidden
			} else {
				file.State = FileStateVisible
			}
		} else {
			file.State = FileStateNotExist
		}

		_, _ = io.WriteString(writer, srv.getHyperlinkByFileInfo(file))
	}
}

func (srv *WebServe) homeHandler(writer http.ResponseWriter, request *http.Request) {
	writer.Header().Set("Content-Type", "text/html; charset=utf-8")
	_, _ = io.WriteString(writer, "<ul>")
	defer func() { _, _ = io.WriteString(writer, "</ul>") }()

	_, _ = io.WriteString(writer, getHyperlinkByIPport("0.0.0.0", srv.Port, "My Shared File"))
	for _, ele := range srv.HostList {
		fmt.Println("添加一个home: ", getHyperlinkByIPport(ele.IP, ele.SharedFilePort, ele.Name))
		_, _ = io.WriteString(writer, getHyperlinkByIPport(ele.IP, ele.SharedFilePort, ele.Name))
	}
}

// 根据IP地址和端口号来返回一个<a>超链接，然后显示一个标签name名
func getHyperlinkByIPport(IP string, port string, name string) string {
	var hyperlink string
	hyperlink = "<li><a href=\"http://" + IP + ":" + port + "/user\" target=\"_blank\">" + name + "</a></li></br>"
	return hyperlink
}

func (srv *WebServe) searchFilesHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	ip, _, _ := net.SplitHostPort(r.RemoteAddr)
	fmt.Println("获取IP: ", ip)
	hostObjs, ok := srv.includeMap[ip]
	IPHidden := false
	if ok {
		IPHidden = hostObjs.IsHidden
	}

	fmt.Println("start searchFiles")
	dirPath, _ := url.QueryUnescape(r.FormValue("folderPath"))
	fmt.Println("读取路径为: ", dirPath)

	files, err := ioutil.ReadDir(dirPath)
	if err != nil {
		fmt.Println("读路径错误，此路径可能不正确: ", dirPath)
		fmt.Println(err)
		return
	}

	_, _ = io.WriteString(w, "<ul>")
	defer func() {
		_, _ = io.WriteString(w, "</ul>")
	}()
	//判断当前dirPath是否在folders中
	isExist := false
	for _, file := range srv.FileInfo {
		fmt.Println("dirPath: ", dirPath, "\tfile.Path", file.Path)
		if strings.Contains(dirPath, file.Path) && dirPath != file.Path {
			isExist = true
			break
		}
	}
	fmt.Println("isExist: ", isExist)

	//根据当前获取的dirPath值得到上一级目录地址
	var preDirPath string
	if !isExist {
		_, _ = io.WriteString(w, "<li><a href=\"user\"> ../ </a></li>")
	} else {
		preDirPath = filepath.Dir(dirPath)
		//写一个上一级的目录
		_, _ = io.WriteString(w, "<li><a href=\""+"/search?folderPath="+preDirPath+"\"> ../ </a></li>")
	}
	// var u string
	for _, file := range files {
		if !file.IsDir() {
			// fmt.Println("File:", file.Name())
			// u = url.Values{"filePath":{dirPath+"/"+file.Name()}}.Encode()
			//判断文件是否是隐藏文件
			if !((srv.Hidden == FileStateHidden || IPHidden) && strings.HasPrefix(file.Name(), ".")) {
				_, _ = io.WriteString(w, "<li><p style=\"color: "+FileColorFile+";display: inline;\">File: </p><a href=\"/download?filePath="+dirPath+"/"+file.Name()+"\">"+file.Name()+"</a></li></br>")
			}
		} else {
			// fmt.Println("Directory:", file.Name())
			// u = url.Values{"folderPath":{dirPath+"/"+file.Name()}}.Encode()
			if !((srv.Hidden == FileStateHidden || IPHidden) && strings.HasPrefix(file.Name(), ".")) {
				_, _ = io.WriteString(w, "<li><p style=\"color: "+FileColorDir+";display: inline;\">Directory: </p><a href=\"/search?folderPath="+dirPath+"/"+file.Name()+"\">"+file.Name()+"</a>"+"</li></br>")
			}
		}
	}

}

func (srv *WebServe) downloadHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Println("start download")
	filePath := r.FormValue("filePath")
	// 获取文件名用于Content-Disposition
	fileName := filepath.Base(filePath)
	fmt.Println("filename : ", fileName)

	// 设置响应头，指示浏览器进行下载
	w.Header().Set("Content-Disposition", "attachment; filename="+fileName)
	// w.Header().Set("Content-Type", "application/octet-stream")
	http.ServeFile(w, r, filePath)
}
